BattleRole = class("BattleRole")

function BattleRole:ctor(...)
	local arg = {...}
	if(#arg ~= 3) then
		GameLog.Error("BattleRole ctor param number is not 3.")
		return
	end 
	
	for i,v in ipairs(arg) do
		if (i == 1) then
			self.id = v.id
			self.name = v.name
			self.hp = v.hp
			self.hpMax = v.hpMax
			self.mp = v.mp
			self.mpMax = v.mpMax 
			self.atk = v.atk
			self.speed = v.speed
			self.weapon = v.weapon
            self.entrance = v.entrance
            self.flyWord = v.flyWord
			--self.skills = v.skills
		elseif (i == 2) then
			GameLog.Log("BattleRole arg 2!!!")
			self.res = v
			self.transform = self.res:GetComponent(typeof(UnityEngine.Transform))
			--self.skeletonAnimation = res:GetComponent(typeof(Spine.Unity.SkeletonAnimation))
			self.animationController = self.res:GetComponent(typeof(SpineAnimationController))
			if(self.animationController == nil) then
				self.animationController = self.res:AddComponent(typeof(SpineAnimationController))
				if(self.animationController == nil) then
					GameLog.Warning("self.animationController is nil")
				end
			end
			self.shaderController = self.res:GetComponent(typeof(SpineShaderController))
			if(self.shaderController == nil) then
				self.shaderController = self.res:AddComponent(typeof(SpineShaderController))
				if(self.shaderController == nil) then
					GameLog.Warning("self.shaderController is nil")
				end
			end
            self.flyWordTransform = self.transform:Find(self.flyWord.name)
            local pos = self.flyWordTransform.localPosition
--            GameLog.Error(pos)
            pos.x = self.flyWord.offset.x + pos.x
            pos.y = self.flyWord.offset.y + pos.y
--            GameLog.Error(pos)
            self.flyWordTransform.localPosition = pos
		elseif (i == 3) then
			self.isFriend = v
		end
	end

	--construct skill
	self.skills = {}
	for i,v in ipairs(arg[1].skills) do
		local skillId = v.id
		self.skills[skillId] = {}
		self.skills[skillId].triggerRound = -1
		self.skills[skillId].skill = v
		if(self.skills[skillId].skill.action_type == 3) then
			self.aoyiActionId = skillId
		end
	end

	self.triggerDeathList = {}
	
	self.isPlayAction = false
    self.eventHPChange= event("eventHPChange")
    self.eventMPChange= event("eventHPChange")
end

function BattleRole:updatePos(pos)
	local position = pos
	position.z = BattleSort.calZValue(position.x, position.y)
	self.transform.position = position
end

function BattleRole:flpY()
	self.transform.eulerAngles = Vector3.New(0,180,0)
end

function BattleRole:playBaseAnim(anim)
	self.animationController:PlayBaseLoopAnimation(anim)
end

function BattleRole:stopBaseAnim()
	self.animationController:StopBaseLoopAnimation()
end

function BattleRole:play(anim, isLoop)
	self.animationController:PlayAnimation(anim, isLoop)
end

function BattleRole:stopAnim()
	self.animationController:StopAnimation()
end

function BattleRole:registerUpdate()
	UpdateBeat:Add(self.update, self)
end

function BattleRole:unregisterUpdate()
	UpdateBeat:Remove(self.update, self)
end

function BattleRole:playAction(actionId)
	self.isPlayAction = true
	if(self.curAction == nil) then
		self.curAction = {}
	else
		tableUtil.clearTable(self.curAction)
	end
	if(self.delAction == nil) then
		self.delAction = {}
	else
		tableUtil.clearTable(self.delAction)
	end
	
	local curPlayAction = Actions[actionId]
	if(curPlayAction.animations ~= nil) then
		for _,v in ipairs(curPlayAction.animations) do
			table.insert(self.curAction, v)
		end
	end

	if(curPlayAction.moves ~= nil) then
		for _,v in ipairs(curPlayAction.moves) do
			table.insert(self.curAction, v)
		end
	end

	if(curPlayAction.events ~= nil) then
		for _,v in ipairs(curPlayAction.events) do
			table.insert(self.curAction, v)
		end
	end

	self.curCameraMoveType = curPlayAction.cameraMoveType
	self.position = self.transform.position
	self.curMove = nil
	self.moveVector = nil
	
	local targetTable = BattleCal.selectTarget(Actions[actionId].target, self.isFriend, self)
	if(#targetTable > 0) then
		--GameLog.Warning("has targetTable")
		self.curSkillTarget = targetTable[1]
		--GameLog.Warning("curSkillTarget name is "..self.curSkillTarget.name)
	else
		--GameLog.Warning("not find targetTable")
		self.curSkillTarget = nil
	end

	self.updateTime = 0
	self.skills[actionId].triggerRound = RoundManager.RoundCount()

	self:playActionStartCamera()

	self:actionStart()
end

function BattleRole:playActionStartCamera()
	if(self.curCameraMoveType == CameraMoveType.RoleCenter) then
		local position = (self.transform.position + self.curSkillTarget.transform.position)/2
		Battle.camera:startDamping(position, 0.3)
		Battle.camera:startScaleByTime(0.3)
	elseif(self.curCameraMoveType == CameraMoveType.ScreenCenter) then
		Battle.camera:startDamping(Vector3.New(0,0,0), 0.3)
		Battle.camera:startScaleByTime(0.3)
	--elseif() then
	end
end

function BattleRole:playMoveCamera(movePos)
	if(self.curCameraMoveType == CameraMoveType.MoveCenter) then
		local position = (movePos + self.curSkillTarget.transform.position) / 2
		Battle.camera:startDamping(position, 0.3)
		Battle.camera:startScaleByTime(0.3)
	end
end

function BattleRole:updateAction()
	--GameLog.Log("BattleRole:updateAction")

	self.updateTime = self.updateTime + Time.deltaTime
	--GameLog.Log("self update action "..self.name)
	--GameLog.Log("self.updateTime "..self.updateTime)
	--GameLog.Log("self action length "..#self.curAction)
	for i,v in ipairs(self.curAction) do
		if(v.start_time <= self.updateTime) then
			if(v.table_type == "animation") then
				self:triggerAnimation(v)
				--GameLog.Warning("insert to delAction triggerAnimation "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "move") then
				self:triggerMove(v)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "effect") then
				self:triggerEffect(v)
				--GameLog.Warning("insert to delAction triggerEffect "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "spell_fly") then
				self:triggerSpellFly(v)
				--GameLog.Warning("insert to delAction triggerSpellFly "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "spell_lightning") then
				self:triggerLightning(v)
				--GameLog.Warning("insert to delAction triggerLightning "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "damage") then
				self:triggerDamage(v)
				--GameLog.Warning("insert to delAction triggerDamage "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "heal") then
				self:triggerHeal(v)
				--GameLog.Warning("insert to delAction triggerHeal "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "buff") then
				self:triggerBuff(v)
				--GameLog.Warning("insert to delAction triggerBuff "..i)
				table.insert(self.delAction,1,i)
			elseif(v.table_type == "death") then
				self:triggerDeath(v)
				table.insert(self.delAction,1,i)
			end	
		end
	end

	for _,v in ipairs(self.delAction) do
		table.remove(self.curAction, v)
	end

	if(#self.delAction > 0) then
		tableUtil.clearTable(self.delAction)
	end 

	if(self.curAnim ~=nil and self.curAnim.start_time + self.curAnim.duration <= self.updateTime) then
		--GameLog.Log("curtime "..self.curAnim.start_time)
		--GameLog.Log("duration "..self.curAnim.duration)
		--GameLog.Log("update animtime ")
		self.curAnim = nil
		self:stopAnim()
	end

	if(#self.curAction <= 0 and self.curAnim == nil) then 
		--GameLog.Log("update action end")
		self.isPlayAction = false
		self.curSkillTarget = nil
		self:actionEnd()
	end

	if(self.curMove ~= nil) then 
		if(self.curMove.start_time + self.curMove.duration <= self.updateTime) then
			--self.transform.position = self.position + self.moveVector
			self:updatePos(self.position + self.moveVector)
			self.curMove = nil
			self.moveVector = nil
		else
			local percent = (self.updateTime - self.curMove.start_time) / self.curMove.duration
			local pos = self.position + self.moveVector * percent
			--GameLog.Warning("pos is "..pos)
			--self.transform.position = pos
			self:updatePos(pos)
		end
	end
end	

function BattleRole:triggerAnimation(anim)
	self.curAnim = anim
	self:play(anim.name, anim.loop)
end

function BattleRole:triggerMove(move)
	--GameLog.Warning("triggerMove")
	if(move.target == MoveTargetType.OldPosition) then
		--GameLog.Warning("MoveTargetType.OldPosition")
		--self.transform.position = self.position
		self:updatePos(self.position)
		self.curMove = nil
		self.moveVector = nil
	elseif(move.target == MoveTargetType.SkillTarget) then
		if(self.curSkillTarget == nil) then
			GameLog.Warning("triggerMove skill target is nil")
			return
		end
		--GameLog.Warning("MoveTargetType.SkillTarget")
		local position = self.curSkillTarget.transform.position
		position.y = position.y + BattleConfigData.attackShiftY --确保攻击的人显示在被攻击的人前面
		if(self.curSkillTarget.isFriend) then 
			position.x = position.x + move.horizontal_distance_from_target
		else
			position.x = position.x - move.horizontal_distance_from_target
		end
		self:playMoveCamera(position)
		self.curMove = move
		self.moveVector = position - self.transform.position
	end
end

function BattleRole:triggerEffect(effect)
	ActionPlayer.playEffect(effect, self)
end

function BattleRole:triggerSpellFly(spellFly)
	local targetTable = BattleCal.selectTarget(spellFly.target, self.isFriend, self)
	if(targetTable ~= nil) then
		for _,v in ipairs(targetTable) do
			ActionPlayer.playSpellFly(spellFly, self, v)
		end
	end
end

function BattleRole:triggerLightning(spellLightning)
	ActionPlayer.playSpellLightning(spellLightning, self, target)
end

function BattleRole:triggerDamage(damage, spellTarget)
    self:modifyMP(40)
	local targetTable = BattleCal.selectTarget(damage.target, self.isFriend, self, spellTarget)
	if(#targetTable > 0) then
		local damageValue = BattleCal.calDamage(1, damage.min, damage.max, damage.extra_damage)
		for _,v in ipairs(targetTable) do
			v:gotDamage(damageValue, damage.beiji_tpl_id)
		end
	end
end

function BattleRole:triggerHeal(heal)
	local targetTable = BattleCal.selectTarget(heal.target, self.isFriend, self)
	if(#targetTable > 0) then
		local healValue = BattleCal.calHeal(heal.min, heal.max, heal.extra_damage)
		for _,v in ipairs(targetTable) do
			v:gotHealEffect(healValue, heal.beiji_tpl_id)
		end
	end
end

function BattleRole:triggerBuff(buff)
	-- body
end

function BattleRole:triggerDeath(death)
	tableUtil.clearTable(self.triggerDeathList)

	for i,v in ipairs(RoleManager.team) do
		table.insert(self.triggerDeathList, v)
	end

	for i,v in ipairs(RoleManager.enemy) do
		table.insert(self.triggerDeathList, v)
	end

	for i,v in ipairs(self.triggerDeathList) do
		v:gotDeathEvent()
	end
end

function BattleRole:actionStart()
	RoundManager.ActionStart()
end

function BattleRole:actionEnd()
	RoundManager.ActionEnd()
end

function BattleRole:getSpeed(value)
	for _,v in ipairs(self.speed) do
		if(v.value == value) then
			return v
		end
	end

	return nil
end

function BattleRole:update()
	--GameLog.Log("BattleRole:update")
	if (self.isPlayAction) then
		self:updateAction()
	elseif(self.isUpdateDelayTime) then
		self:updateDelayFunction()
	end
end

function BattleRole:isDead()
	if(self.hp <= 1e-6) then
		return true
	end

	return false
end

function BattleRole:gotDamage(damage, beijiId)
	self:gotDamageValue(damage)
	-- play effect
	local beijiData = Beiji[beijiId]
    FlyWordBar:showHPDec(self, -damage)
    self:modifyMP(30)
	ActionPlayer.playEffect(beijiData, self)
end

function BattleRole:gotDamageValue(damage)
--	GameLog.Warning(self.name.." got damage"..damage)
	self.hp = self.hp - damage
	self.hp = Mathf.Clamp(self.hp, 0, self.hpMax)
    self.eventHPChange()
    self:play("hitted", false)
    --[[
	if(self:isDead()) then
		self:stopBaseAnim()
		self:play("dead", false)
		self:fadeOut(1.0, 2.0)
		RoleManager.removeDeadRole(self)
	else 
		self:play("hitted", false)
	end
	]]
end

function BattleRole:gotHealEffect(healValue, beijiId)
--	GameLog.Error(self.name.." got healValue".. healValue)
	self.hp = self.hp + healValue
	self.hp = Mathf.Clamp(self.hp, 0, self.hpMax)
    FlyWordBar:showHPInc(self, healValue)
    self.eventHPChange()
--    self:play("hitted", false)
	local beijiData = Beiji[beijiId]
	ActionPlayer.playEffect(beijiData, self)
end

function BattleRole:gotDeathEvent()
	if(self:isDead()) then
		self:stopBaseAnim()
		self:play("dead", false)
		self:fadeOut(1.0, 2.0)
		RoleManager.removeDeadRole(self)
	end
end

function BattleRole:modifyMP(damage)
--	GameLog.Warning(self.name.." modify MP ="..damage)
    --if(self.mp >= self.mpMax) then return end
	self.mp = self.mp + damage
    if(self.mp >= self.mpMax) then
        self.mp = self.mpMax
        self.isMPFull = true
    else
        self.isMPFull = false
    end
    self.eventMPChange()
end

function BattleRole:castAoyi()
	if(self.aoyiActionId == nil) then
		GameLog.Warning("role " .. self.name .. " does not have aoyi!")
		return
	end

	RoundManager.InsertAoyiAction(self, self.aoyiActionId)	
	self:modifyMP(-self.mp)
end

function BattleRole:updateDelayFunction()
	--GameLog.Warning("updateDelayFunction")
	self.totalDelayTime = self.totalDelayTime + Time.deltaTime
	if(self.totalDelayTime >= self.delayTime) then
		self.shaderController:StartFade(self.fadeOutTime)
		self.isUpdateDelayTime = false
	end
end

function BattleRole:fadeOut(delayTime, fadeOutTime)
	--GameLog.Warning("fadeout")
	self.isUpdateDelayTime = true
	self.delayTime = delayTime
	self.fadeOutTime = fadeOutTime
	self.totalDelayTime = 0.0
end


